﻿enum MoveDirection
{
    MoveDirectionUp = 0,
    MoveDirectionDown,
    MoveDirectionLeft,
    MoveDirectionRight
}


class TextCursor
{
    private _position: TextPosition;
    private _selectionRange: TextSelectionRange;
    private _textView: TextView;
    private _cursorView: HTMLDivElement;
    constructor(line: number = 0, character: number = 0)
    {
        this._position = new TextPosition(line, character);
        this._selectionRange = new TextSelectionRange();
        this._selectionRange.start = this._position;
        this._selectionRange.end = this._position;
    }

    moveUp(): void
    {
        this._position.line--;
        this._position = this._checkBounds(this._position);
        this._setCursorPosition(this._position);
    }
    moveLeft(): void
    {
        this._position.character--;
        this._position = this._checkBounds(this._position);
        this._setCursorPosition(this._position);
    }
    moveRight(): void
    {
        this._position.character++;
        this._position = this._checkBounds(this._position);
        this._setCursorPosition(this._position);
    }
    moveDown(): void
    {
        this._position.line++;
        this._position = this._checkBounds(this._position);
        this._setCursorPosition(this._position);
    }
    
    get position(): TextPosition
    {
        return this._position;
    }
    set position(p: TextPosition)
    {
        this._position = p;
        this._setCursorPosition(this._position);
    }

    set textView(t: TextView)
    {
        this._textView = t;
        this._cursorView = document.createElement('div');
        this._cursorView.style.position = 'absolute';
        this._cursorView.style.width = '1px';
        this._cursorView.style.height = this._textView.font.getHeight() + 'px';
        this._cursorView.style.backgroundColor = "#000000";
        this._textView.wrapper.appendChild(this._cursorView);
        this._setCursorPosition(this._position);
    }

    selectedLines(): number[][]
    {
        var start: TextPosition = this._selectionRange.start;
        var end: TextPosition = this._selectionRange.end;

        if (start.compare(end) === ComparisonResult.OrderedDescending)
        {
            start = this._selectionRange.end;
            end = this._selectionRange.start;
        }

        var ranges = [];
        if (start.line === end.line)
            ranges[start.line] = [start.character, end.character];
        else
        {
            ranges[start.line] = [start.character, -1];

            for (var line = start.line + 1; line < end.line; line++)
                ranges[line] = [0, -1];

            ranges[end.line] = [0, end.character];
        }

        return ranges;
    }

    isEmpty(): boolean
    {
        return this._selectionRange.isEmpty();
    }

    private _setCursorPosition(pos: TextPosition):void
    {
        var metrics = this._textView.font,
            offsetX = pos.character * metrics.getWidth(),
            offsetY = pos.line * metrics.getHeight();
        this._cursorView.style.left = offsetX + 'px';
        this._cursorView.style.top = offsetY + 'px';

    }

    private _checkBounds(pos: TextPosition): TextPosition
    {
        var newPos = pos,
            currPos = this.position;

        if (newPos.character < 0)
        {
            // Wraparound for lines
            if ((newPos.line === currPos.line) && (newPos.line > 0))
            {
                --newPos.line;
                newPos.character = this._textView.delegate.lineLength(newPos.line);
            } else
            {
                newPos.character = 0;
            }
        }

        // Checking upper bounds
        var lineCount = this._textView.delegate.lineCount();
        if (newPos.line >= lineCount)
            newPos.line = lineCount - 1;
        var characterCount = this._textView.delegate.lineLength(newPos.line);
        if (newPos.character > characterCount)
        {
            // Wraparound for lines
            if ((newPos.line === currPos.line) && newPos.line < lineCount - 1)
            {
                ++newPos.line;
                newPos.character = 0;
            } else
            {
                newPos.character = characterCount;
            }
        }

        return newPos;
    }


}